
def randomly_moving_checkerboard_search_settings():
    '''
    This function tells you what settings are needed and in what order for this stimulus.
    Inputs:
        None
    Returns:
        settings        : A list of tupples.  In each tupple is
                            (setting_name, setting_description, default_value).
                          The list is of length num_settings + 1, so that the final
                             value in the list is True/False wether or not the stimulus
                             can be triggered via the parallel port or not.
    '''
    settings = []
    settings.append( ('check_size',
                     'The size of the checkerboard squares. (pixels)',
                     80 ))
    settings.append( ('distance',
                     'How far the checkerboard pattern moves. (pixels)',
                     500 ))
    settings.append( ('duration',
                     'The amount of time the stimulus will move. (seconds)',
                     3.5 ))
    settings.append( ('wait_time',
                     'The amount of time after stimulus movement. (seconds)',
                     1.0 ))
    settings.append( ('win_size',
                     'The dimensions of the stimulus delivery window. (pixels) [list]',
                     [1440,900] ))
    settings.append( ('refresh_rate',
                     'The number of screen refreshes per second. (Hz)',
                     60 ))
    settings.append( ('random_seed',
                     'The number to seed the random number generator.',
                     40 ))
    settings.append(True) # this stimulus can be triggered
    return settings


def find_x_y(distance, angle, speed, num_frames):
    """
    Returns the starting position and the dx, dy needed to move a bar from that position to the opposite
        side of the rim.
    """
    import scipy
    # find the x,y coordinates of the starting point
    start_x = -distance/2 * scipy.cos(angle*scipy.pi/180.0)
    start_y = -distance/2 * scipy.sin(angle*scipy.pi/180.0)

    dx = speed * scipy.cos(angle*scipy.pi/180.0)
    dy = speed * scipy.sin(angle*scipy.pi/180.0)

    x = scipy.array([start_x + i*dx for i in xrange(num_frames)])
    y = scipy.array([start_y + i*dy for i in xrange(num_frames)])

    return x,y


def randomly_moving_checkerboard_search_runtime(check_size, distance, 
                                                duration, wait_time, 
                                                win_size, refresh_rate, 
                                                random_seed):
    """
    Calculate and return the number of seconds that this stimulus will need to run, after being triggered.
    """
    return duration + wait_time + 0.99 # 0.99 added so rounding is always up.

def randomly_moving_checkerboard_search(check_size, distance, duration, wait_time, 
                                  win_size, refresh_rate, random_seed, 
                                  window=None, eye_cup=None, rf=None, preview=True):
    """
    This stimulus is a full field checkerboard, which moves in random directions.
    Inputs:
        check_size      : how large the check is, in normalized units
        distance        : how far the checkerboard pattern moves during 'duration'
        duration        : the time where the stimulus will be moving
        wait_time       : the time after movement, before next movement.
        win_size        : dimensions of the screen in pixels, (1440,900) is default
        refresh_rate    : refresh rate in Hz of the video, 60.0 is default.
        random_seed     : the seed for the random number generator.
        --- kwargs --
        window          : a psychopy.visual Window object, if not passed it will be constructed.
                        :    if passed it will not be closed (a blank screen will be drawn)
        eye_cup         : just there to keep interface consistent
        rf              : just there to keep interface consistent
        preview         : If false the program will wait for a pulse trigger, otherwise it won't.
    Returns:
        times     : The times when frames were shown, with zero being the first frame time.
    """
    from psychopy import core, event, visual
    import scipy
    import random

    # seed the random number generator
    random.seed(random_seed)

    # how many frames we'll display
    num_frames = int(duration*refresh_rate)
    # how the bar should move each frame
    speed      = (distance*1.0)/(num_frames*1.0)

    # rgb = 1.0 is white, and sets that as the default background
    if window == None: # if no window object passed, create one.
        myWin = visual.Window( win_size, allowGUI=False, fullscr=False, pos=(0,-900), rgb=1.0,)
    else: # window object was passed, so use it.
        myWin = window

    # ---------------------------
    # -- Generate the stimulus --
    # ---------------------------
    texture = scipy.ones((64,64),dtype=scipy.float64)*-1.0
    for i in xrange(64):
        for j in xrange(64):
            # odd checks are already black
            if (i+j)%2 == 0: # even index of check
                texture[i][j] = 1.0 # make white

    checkerboard = visual.PatchStim( myWin, tex=texture, size=(64*check_size,64*check_size), \
                            pos=(0.0,0.0), units='pix' )

    # --------------------------------------------------
    # -- Show the Stimulus (or wait and then show it) --
    # --------------------------------------------------

    # -----------------------
    # --  WAIT FOR A PULSE --
    # -----------------------
    if not preview:
        import parallel
        from helper_codes.pport_functions import wait_for_pulse
        p = parallel.Parallel()     # get access to the parallel port
        print "Waiting for pulse..."
        wait_for_pulse(p) # poll the parallel port for a pulse every pport_dt seconds
    else:
        print "Not Waiting for pulse..."

    # start keeping track of time
    trialClock = core.Clock()       # start the clock
    times = [0.0]                   # time begins at 0.0

    keep_looping = True
    while keep_looping:
        angle = random.random()*360.0
        x,y = find_x_y(distance, angle, speed, num_frames)
        myWin.setRecordFrameIntervals()

        # --------------------------
        # --  SHOW THE STIMULUS   --
        # --------------------------
        for n in xrange(num_frames): #for some number of frames
            # move the bar, for the next time we draw it.
            checkerboard.setPos( (x[n], y[n] ) , units='norm')
            # draw the objects to the back buffer
            checkerboard.draw()
            # flip the back buffer to the front and the front to the back
            myWin.flip()
            # keep track of when buffers were flipped

            #handle key presses each frame
            for key in event.getKeys():
                if key in ['escape','q']:
                    keep_looping = False
            if keep_looping == False:
                break

        core.wait(wait_time) # wait some seconds after each movement

    diffs = myWin.frameIntervals[1:]
    times = [0.0]
    for diff in diffs:
        times.append(times[-1]+diff)
        
    if window == None: # no window object was passed.
        myWin.close()
    
    return times


if __name__ == '__main__':
    # ---------------------------------
    # -- Set the stimulus parameters --
    # ---------------------------------
    check_size = 80                # in normalized units
    distance   = 1000                # in normalized units
    duration   = 3.0                # in seconds
    wait_time  = 0.0                # in seconds

    # display parameters
    win_size = (1440,900)  # in pixels
    refresh_rate = 60.0    # in Hz
    random_seed = 40
    times = randomly_moving_checkerboard_search(check_size, distance, duration, wait_time, 
                                  win_size, refresh_rate, random_seed, preview=True)
    from analyze_frame_times import analyze_frame_times as aft
    aft(times)


